#pragma once
#include <iostream>
#include <string>
#include "open_hash.hpp"
#include "hash_func.hpp"

namespace test
{

template<class K, class V, class Hash = hash<K>>
class unordered_map
{
private:
    struct KeyOfVal
    {
        const K& operator()(const std::pair<const K, V>& kv) const
        {
            return kv.first;
        }
    };

public:
    typedef hash_table<K, std::pair<const K, V>, Hash, KeyOfVal> rep_type;
    typedef typename rep_type::iterator iterator;
    typedef typename rep_type::const_iterator const_iterator;

public:
    std::pair<iterator, bool> insert(const std::pair<K, V>& kv)
    {
        return _ht.insert(kv);
    }

    size_t erase(const K& key)
    {
        return _ht.erase(key);
    }

    iterator find(const K& key)
    {
        return _ht.find(key);
    }

    iterator begin()
    {
        return _ht.begin();
    }

    iterator end()
    {
        return _ht.end();
    }

    const_iterator begin() const
    {
        return _ht.begin();
    }

    const_iterator end() const
    {
        return _ht.end();
    }

    V& operator[](const K& key)
    {
        return _ht.insert({key, V()}).first->second;
    }

private:
    rep_type _ht;
};

class date
{
	friend struct hash_date;
public:
	date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}

	bool operator==(const date& d) const
	{
		return _year == d._year
			&& _month == d._month
			&& _day == d._day;
	}

	friend std::ostream& operator<<(std::ostream& _cout, const date& d);
private:
	int _year;
	int _month;
	int _day;
};

std::ostream& operator<<(std::ostream& _cout, const date& d)
{
    _cout << d._year << "-" << d._month << "-" << d._day;
    return _cout;
}

struct hash_date
{
    size_t operator()(const date& d) const
    {
        size_t n = d._year;
        n *= 31;
        n += d._month;
        n *= 31;
        n += d._day;
        n *= 31;
        return n;
    }
};


void test_unordered_map()
{
    unordered_map<int, int> m;
    m.insert({1, 1});
    m.insert({2, 2});
    m.insert({3, 3});
    m.insert({4, 4});
    m.insert({5, 5});
    m.insert({6, 6});

    unordered_map<int, int>::iterator it = m.begin();
    while (it != m.end())
    {
        std::cout << it->first << ":" << it->second << " ";
        ++it;
    }
    std::cout << std::endl;

    std::string arr[]
        = {"xg","xg","pg","xg","pg","pg","xg","pg","xj","pg","xj","li"};

    unordered_map<std::string, int> count_map;
    for (auto& e : arr)
    {
        unordered_map<std::string, int>::iterator ret = count_map.find(e);
        if (ret == count_map.end())
        {
            count_map.insert(make_pair(e, 1));
        }
        else
        {
            ret->second++;
        }
    }

    for (auto& e : arr)
    {
        count_map[e]++;
    }

    for (auto& kv: count_map)
    {
        std::cout << kv.first << ": " << kv.second << std::endl;
    }

    date d1(2023, 3, 13);
    date d2(2019, 4, 10);
    date d3(2023, 3, 11);
    date d4(2022, 2, 13);
    date d5(2022, 2, 13);
    date d6(2021, 5, 23);
    date d7(2021, 5, 23);

    date d[] = {d1, d2, d3, d4, d5, d6, d7};
    unordered_map<date, int, hash_date> cm;
    for (auto& e : d)
    {
        cm[e]++;
    }

    for (auto& e : cm)
    {
        std::cout << e.first << ":" << e.second << std::endl;
    }

    const unordered_map<int, int> cum;
    unordered_map<int, int>::const_iterator cit = cum.begin();
}

}
